package com.syf.kit.core.dao.sql;

import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ResultSetHandle {

    /**
     * 将ResultSet转换为List<Map<String, Object>>
     */
    public static List<Map<String, Object>> toListMap(ResultSet rs) throws SQLException {
        List<Map<String, Object>> list = new ArrayList<>();
        ResultSetMetaData metaData = rs.getMetaData();
        while (rs.next()) {
            Map<String, Object> recordMap = new HashMap<>();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                recordMap.put(metaData.getColumnLabel(i), rs.getObject(metaData.getColumnLabel(i)));
            }
            list.add(recordMap);
        }
        return list;
    }

    /**
     * 将查询的数据转换成实体类
     *
     * @param rs 查询结果集
     * @param clazz 转换实体类
     * @return
     * @throws Exception
     */
    public static List toObjectList(ResultSet rs, Class clazz)  {
        List dataList = new ArrayList<>();
        try {
            ResultSetMetaData metaData = rs.getMetaData();
            // 查询结果列数
            int columnCount = metaData.getColumnCount();
            if(columnCount > 0){
                boolean basicDataType = isBasicDataType(clazz);
                if(basicDataType){
                    while (rs.next()){
                        Object basicData = getBasicData(rs, clazz);
                        dataList.add(basicData);
                    }
                }else{
                    // 获取类声明的属性
                    Field[] fields = clazz.getDeclaredFields();
                    while (rs.next()){
                        // 构造类实例对象
                        Object clazzInstance = clazz.newInstance();
                        // 寻找列名对应的对象属性并赋值
                        for(int col=1; col<= columnCount; col++){
                            Object columnVal = rs.getObject(col);
                            for(int i=0; i< fields.length; i++){
                                // 获取类申明的属性值
                                Field field = fields[i];
                                // 如果匹配进行赋值
                                if(field.getName().equalsIgnoreCase(metaData.getColumnName(col))){
                                    boolean accessible = field.isAccessible();
                                    field.setAccessible(true);
                                    // 从数据库中获取到的是BigBigDecimal类型的数据，需要转换成包装类的对象
                                    if(columnVal instanceof BigDecimal){
                                        /*
                                        Constructor<?> dc = field.getType().getDeclaredConstructor(String.class);
                                        columnVal = dc.newInstance(columnVal.toString());
                                        field.set(clazzInstance, columnVal);
                                        */
                                        setFieldNumberVal(clazzInstance, field, rs, col);
                                    }else if(columnVal instanceof Clob){
                                        field.set(clazzInstance, clobToString((Clob)columnVal));
                                    } else{
                                        field.set(clazzInstance, columnVal);
                                    }
                                    field.setAccessible(accessible);
                                }
                            }
                        }
                        dataList.add(clazzInstance);
                    }
                }
            }
        } catch (SQLException se){
            throw new RuntimeException("查询数据转换异常");
        }catch (Exception e){
            throw new RuntimeException("查询数据转换异常");
        }
        return dataList;
    }

    /**
     *
     * 类私有属性为数字类型，使用此方法对属性进行赋值
     *
     * @param clazzInstance
     * @param field
     * @param rs
     * @param columnIndex
     * @throws Exception
     */
    private static void setFieldNumberVal(Object clazzInstance, Field field, ResultSet rs, int columnIndex) throws Exception {
        /**
         * 类变量类型
         *   int,double,float等是基本数据类型
         */
        String fieldTypeName = field.getType().getName();
        //logger.info("打印参数：field.getName()="+field.getName()+", field.getType().getName()="+fieldTypeName);
        if("long".equals(fieldTypeName)){
            field.set(clazzInstance, rs.getLong(columnIndex));
        }
        else if("int".equals(fieldTypeName)){
            field.set(clazzInstance, rs.getInt(columnIndex));
        }
        else if("short".equals(fieldTypeName)){
            field.set(clazzInstance, rs.getShort(columnIndex));
        }
        else if("double".equals(fieldTypeName)){
            field.set(clazzInstance, rs.getDouble(columnIndex));
        }
        else if("float".equals(fieldTypeName)){
            field.set(clazzInstance, rs.getFloat(columnIndex));
        }
        else if("boolean".equals(fieldTypeName)){
            field.set(clazzInstance, rs.getBoolean(columnIndex));
        }
        else{
            Constructor<?> dc = field.getType().getDeclaredConstructor(String.class);
            Object columnVal = dc.newInstance(rs.getString(columnIndex));
            field.set(clazzInstance, columnVal);
        }
    }

    /**
     * 判断类的类型是否为8大基本类型包装类
     *
     * @param clazz
     * @return
     */
    private static boolean isBasicDataType(Class clazz){
        boolean result = false;
        String clazzName = clazz.getName();
        if("java.lang.String".equals(clazzName) || "java.lang.Character".equals(clazzName)
                || "java.lang.Double".equals(clazzName) || "java.lang.Float".equals(clazzName)
                || "java.lang.Integer".equals(clazzName) || "java.lang.Long".equals(clazzName)
                || "java.lang.Short".equals(clazzName) || "java.lang.Boolean".equals(clazzName)  ){
            result = true;
        }
        return result;
    }

    /**
     * 判断类的类型是否为8大基本类型包装类
     *
     * @param rs
     * @param clazz
     * @return
     * @throws Exception
     */
    private static Object getBasicData(ResultSet rs, Class clazz) throws Exception {
        Object value = null;
        String clazzName = clazz.getName();
        if("java.lang.String".equals(clazzName)){
            value = new String(rs.getString(1));
        }
        if("java.lang.Character".equals(clazzName)){
            value = new String(rs.getString(1));
        }
        if("java.lang.Double".equals(clazzName)){
            value = new Double(rs.getDouble(1));
        }
        if("java.lang.Float".equals(clazzName)){
            value = new Float(rs.getFloat(1));
        }
        if("java.lang.Integer".equals(clazzName)){
            value = new Integer(rs.getInt(1));
        }
        if("java.lang.Long".equals(clazzName)){
            value = new Long(rs.getInt(1));
        }
        if("java.lang.Short".equals(clazzName)){
            value = new Short(rs.getShort(1));
        }
        if("java.lang.Boolean".equals(clazzName)){
            value = new Boolean(rs.getBoolean(1));
        }
        return value;
    }

    /**
     * 将clob数据库字段转换成字符串
     * @param clob
     * @return
     * @throws SQLException
     * @throws IOException
     */
    private static String clobToString(Clob clob) throws  SQLException, IOException {
        StringBuilder buff = new StringBuilder();
        if(clob!=null){
            Reader reader = clob.getCharacterStream();
            BufferedReader buffReader = new BufferedReader(reader);
            String readLine = buffReader.readLine();
            while (!StringUtils.isEmpty(readLine)){
                buff.append(readLine);
                readLine = buffReader.readLine();
            }
        }
        return buff.toString();
    }

}
